package com.sxkj.common.pay.xypay;

import com.sxkj.common.utils.RequestUtil;
import com.sxkj.common.utils.SignUtils;
import com.sxkj.common.utils.StringUtils;
import com.sxkj.common.utils.XmlUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.sxkj.common.utils.SignUtils.SignType.HMACSHA256;


/**
 * @author Zhang Xingliang
 * @description 兴业支付接口类优化和集成
 * @date 21:34 2019/12/27
 **/
public class XYPay {

    private SwiftpassConfig config;
    private XYPayConstants.SignType signType;

    public XYPay(SwiftpassConfig config) throws Exception {
        this.config = config;
    }

    /**
     * @param data 向xypay post的请求数据
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @throws Exception
     * @author Zhang Xingliang
     * @description 兴业扫付款码
     * @date 17:05 2019/12/26
     **/
    public Map<String, String> micropay(Map<String, String> data) throws Exception {
        return this.micropay(data, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
    }

    /**
     * @param data          向xypay post的请求数据
     * @param connectTimeoutMs 连接超时时间，单位是毫秒
     * @param readTimeoutMs    读超时时间，单位是毫秒
     * @return API返回数据
     * @throws Exception
     * @author Zhang Xingliang
     * @description 兴业扫付款码
     * @date 17:05 2019/12/26
     */
    public Map<String, String> micropay(Map<String, String> data, int connectTimeoutMs, int readTimeoutMs) throws Exception {

        if (StringUtils.isBlank(data.get("mch_id"))) {
            throw new Exception("缺少必要参数：mch_id");
        }
        if (StringUtils.isBlank(data.get("key"))) {
            throw new Exception("缺少必要参数：key");
        }

        if (StringUtils.isBlank(data.get("out_trade_no"))) {
            throw new Exception("缺少必要参数：out_trade_no");
        }

        if (StringUtils.isBlank(data.get("total_fee"))) {
            throw new Exception("缺少必要参数：total_fee");
        }

        if (StringUtils.isBlank(data.get("auth_code"))) {
            throw new Exception("缺少必要参数：auth_code");
        }

        Map<String, String> requestMap = new HashMap<>();
        requestMap.put("service", XYPayConstants.microPayService);
        requestMap.put("mch_id", data.get("mch_id"));
        requestMap.put("out_trade_no", data.get("out_trade_no"));
        requestMap.put("total_fee", data.get("total_fee"));
        requestMap.put("auth_code", data.get("auth_code"));
        requestMap.put("device_info", data.get("device_info") == null ? "pos001" : data.get("device_info"));
        String key = data.get("key");
        String respXml = RequestUtil.requestWithoutCert(XYPayConstants.GATEWAY_URL,
                this.fillRequestData(requestMap, key), this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
        return this.responseSignXml(respXml, key);
    }

    /**
     * 处理 HTTPS API返回数据，转换成Map对象。return_code为SUCCESS时，验证签名。
     *
     * @param xmlStr API返回的XML格式数据
     * @return Map类型数据
     * @throws Exception
     */
    public Map<String, String> responseSignXml(String xmlStr, String key) throws Exception {
        String status = "status";
        Map<String, String> respData = XmlUtils.xmlToMap(xmlStr);
        if (respData.containsKey(status)) {
            status = respData.get(status);
        } else {
            throw new Exception(String.format("No `status` in XML: %s", xmlStr));
        }

        if (status.equals(XYPayConstants.SUCCESS)) {
            if (respData.containsKey("sign") && SignUtils.checkSign(respData, key)) {
                return respData;
            } else {
                throw new Exception(String.format("Invalid sign value in XML: %s", xmlStr));
            }

        } else if (StringUtils.isNotBlank(status)) {
            return respData;
        }
        throw new Exception(String.format("return_code value %s is invalid in XML: %s", status, xmlStr));
    }

    /**
     * 处理 HTTPS API返回数据，转换成Map对象。return_code为SUCCESS时，不校验验证签名。
     *
     * @param xmlStr API返回的XML格式数据
     * @return Map类型数据
     * @throws Exception
     */
    public Map<String, String> responseUnsignXml(String xmlStr) throws Exception {
        String status = "status";
        Map<String, String> respData = XmlUtils.xmlToMap(xmlStr);
        if (respData.containsKey(status)) {
            status = respData.get(status);
        } else {
            throw new Exception(String.format("No `status` in XML: %s", xmlStr));
        }
        if (status.equals(XYPayConstants.SUCCESS)) {
            return respData;
        } else if (StringUtils.isNotBlank(status)) {
            return respData;
        }
        throw new Exception(String.format("return_code value %s is invalid in XML: %s", status, xmlStr));
    }

    /**
     * 向 Map 中添加 nonce_str、sign <br>
     * 该函数适用于填充数据 生成签名
     *
     * @param reqData
     * @return
     * @throws Exception
     */
    public Map<String, String> fillRequestData(Map<String, String> reqData, String key) throws Exception {
        reqData.put("body", this.config.getBody());
        reqData.put("mch_create_ip", this.config.getMchCreateIp());
        reqData.put("nonce_str", SignUtils.nonceStr());
        if (XYPayConstants.MD5.equalsIgnoreCase(this.config.getSignType())) {
            reqData.put("sign", SignUtils.sign(reqData, key));
        } else if (XYPayConstants.HMACSHA256.equalsIgnoreCase(this.config.getSignType())) {
            reqData.put("sign", SignUtils.sign(reqData, key, HMACSHA256));
        } else {//md5加密
            reqData.put("sign", SignUtils.sign(reqData, key));
        }
        return reqData;
    }

    /**
     * @param reqData 向xypay post的请求数据
     * @return API返回数据
     * @throws Exception
     * @author Zhang Xingliang
     * @description 订单状态查询
     * @date 17:05 2019/12/26
     */
    public Map<String, String> unifiedTradeQuery(Map<String, String> reqData) throws Exception {
        return this.unifiedTradeQuery(reqData,  this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
    }

    /**
     * @param data          向xypay post的请求数据
     * @param connectTimeoutMs 连接超时时间，单位是毫秒
     * @param readTimeoutMs    读超时时间，单位是毫秒
     * @return API返回数据
     * @throws Exception
     * @author Zhang Xingliang
     * @description 订单状态查询
     * @date 17:05 2019/12/26
     */
    public Map<String, String> unifiedTradeQuery(Map<String, String> data, int connectTimeoutMs, int readTimeoutMs) throws Exception {

        Map<String, String> requestMap = new HashMap<>();
        requestMap.put("mch_id", data.get("mch_id"));
        requestMap.put("out_trade_no", data.get("out_trade_no"));
        requestMap.put("transaction_id", data.get("transaction_id"));
        requestMap.put("sign_type", data.get("sign_type"));
        requestMap.put("device_info", data.get("device_info") == null ? "pos001" : data.get("device_info"));
        requestMap.put("service", XYPayConstants.unifiedTradeQueryService);
        String key = data.get("key");
        String respXml = RequestUtil.requestWithoutCert(XYPayConstants.GATEWAY_URL,
                this.fillRequestData(requestMap, key), connectTimeoutMs, readTimeoutMs);
        return this.responseSignXml(respXml, key);
    }

    /**
     * @param reqData 向xypay post的请求数据
     * @return API返回数据
     * @throws Exception
     * @author Zhang Xingliang
     * @description 撤销订单
     * @date 17:05 2019/12/26
     */
    public Map<String, String> unifiedMicropayReverse(Map<String, String> reqData) throws Exception {
        return this.unifiedMicropayReverse(reqData, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
    }

    /**
     * @param data          向xypay post的请求数据
     * @param connectTimeoutMs 连接超时时间，单位是毫秒
     * @param readTimeoutMs    读超时时间，单位是毫秒
     * @return API返回数据
     * @throws Exception
     * @author Zhang Xingliang
     * @description 撤销订单
     * @date 17:05 2019/12/26
     */
    public Map<String, String> unifiedMicropayReverse(Map<String, String> data, int connectTimeoutMs, int readTimeoutMs) throws Exception {

        Map<String, String> requestMap = new HashMap<>();
        requestMap.put("mch_id", data.get("mch_id"));
        requestMap.put("out_trade_no", data.get("out_trade_no"));
        requestMap.put("transaction_id", data.get("transaction_id"));
        requestMap.put("sign_type", data.get("sign_type"));
        requestMap.put("service", XYPayConstants.unifiedMicropayReverseService);

        String key = data.get("key");
        String respXml = RequestUtil.requestWithoutCert(XYPayConstants.GATEWAY_URL,
                this.fillRequestData(requestMap, key), connectTimeoutMs, readTimeoutMs);
        return this.responseSignXml(respXml, key);
    }

    /**
     * @param data 向xypay post的请求数据
     * @return API返回数据
     * @throws Exception
     * @author Zhang Xingliang
     * @description 扫码支付
     * @date 17:05 2019/12/26
     */
    public Map<String, String> weixinNative(Map<String, String> data) throws Exception {
        return this.weixinNative(data, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
    }

    /**
     * @param data          向xypay post的请求数据
     * @param connectTimeoutMs 连接超时时间，单位是毫秒
     * @param readTimeoutMs    读超时时间，单位是毫秒
     * @return API返回数据
     * @throws Exception
     * @author Zhang Xingliang
     * @description 扫码支付
     * @date 17:05 2019/12/26
     */
    public Map<String, String> weixinNative(Map<String, String> data, int connectTimeoutMs, int readTimeoutMs) throws Exception {


        Map<String, String> requestMap = new HashMap<>();
        requestMap.put("mch_id", data.get("mch_id"));
        requestMap.put("out_trade_no", data.get("out_trade_no"));
        requestMap.put("transaction_id", data.get("transaction_id"));
        requestMap.put("sign_type", data.get("sign_type"));
        requestMap.put("service", XYPayConstants.wxPayService);
        String key = data.get("key");
        String respXml = RequestUtil.requestWithoutCert(XYPayConstants.GATEWAY_URL,
                this.fillRequestData(data, key), connectTimeoutMs, readTimeoutMs);
        return this.responseSignXml(respXml, key);
    }

    /**
     * @param data 向xypay post的请求数据
     * @return API返回数据
     * @throws Exception
     * @author Zhang Xingliang
     * @description 公众号小程序支付
     * @date 17:05 2019/12/26
     */
    public Map<String, String> weixinJsPay(Map<String, String> data) throws Exception {
        return this.weixinJsPay(data, this.config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
    }

    /**
     * @param data          向xypay post的请求数据
     * @param connectTimeoutMs 连接超时时间，单位是毫秒
     * @param readTimeoutMs    读超时时间，单位是毫秒
     * @return API返回数据
     * @throws Exception
     * @author Zhang Xingliang
     * @description 公众号小程序支付
     * @date 17:05 2019/12/26
     */
    public Map<String, String> weixinJsPay(Map<String, String> data, int connectTimeoutMs, int readTimeoutMs) throws Exception {

        Map<String, String> requestMap = new HashMap<>();
        requestMap.put("mch_id", data.get("mch_id"));
        requestMap.put("out_trade_no", data.get("out_trade_no"));
        requestMap.put("transaction_id", data.get("transaction_id"));
        requestMap.put("sign_type", data.get("sign_type"));
        requestMap.put("service", XYPayConstants.wxjsPayService);
        String key = data.get("key");
        String respXml = RequestUtil.requestWithoutCert(XYPayConstants.GATEWAY_URL,
                this.fillRequestData(requestMap, key), connectTimeoutMs, readTimeoutMs);
        return this.responseSignXml(respXml, key);
    }



}
